﻿using FreeRobot.Common;
using FreeRobot.View.ViewEx;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using static System.Windows.Forms.AxHost;

namespace FreeRobot.View
{
    public unsafe class RobotMap : Control
    {
        public RobotMap()
        {
            SetStyle(
               ControlStyles.ResizeRedraw
               | ControlStyles.DoubleBuffer
               | ControlStyles.UserPaint
               | ControlStyles.AllPaintingInWmPaint
               | ControlStyles.SupportsTransparentBackColor,
               true
               );
        }
        private int _row = 20;
        public int MapRow
        {
            get
            {
                return _row;
            }
            set
            {
                if (value > 1)
                {
                    _row = value;
                    this.Invalidate();
                }
            }
        }
        private int _column = 20;
        public int MapColumn
        {
            get { return _column; }
            set
            {
                if (value > 1)
                {
                    _column = value;
                    this.Invalidate();
                }
            }
        }
        const int _blackSize = 5;
        private Point _robotPoint = new Point(0, 0);
        public Point RobotPoint
        {
            get { return _robotPoint; }
            set
            {
                if (value.X < 0 || value.Y < 0 || value.X >= _column || value.Y >= _row) return;
                if (_cellInfo != null)
                {
                    if (_cellInfo.Map[value.Y, value.X] == 1) return;

                    Completed = _cellInfo.End.X == value.X && _cellInfo.End.Y == value.Y;
                }
                _robotPoint = value;
                this.ExecBeginInvoke(() =>
                {
                    this.Invalidate();
                });
            }
        }
        private float _angle = 0;
        public float Angle
        {
            get
            {
                return _angle;
            }
            set
            {
                _angle = value;
                if (_angle <= -360f)
                    _angle = 0f;
                this.ExecBeginInvoke(() =>
                {
                    this.Invalidate();
                });
            }
        }
        private Image _robotImage;
        public Image RobotImage
        {
            get { return _robotImage; }
            set
            {
                _robotImage = value;
                this.Invalidate();
            }
        }
        public void Reset()
        {
            RobotPoint = new Point(0, 0);
            Angle = 0f;
            Completed = false;
        }
        private CellInfo _cellInfo;
        public void LoadMap(CellInfo cellInfo)
        {
            RobotPoint = cellInfo.Start;
            _cellInfo = cellInfo;
            this.Invalidate();
        }
        public bool Completed { get; set; }
        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.Smooth();

            Pen pen = new Pen(Color.Black);
            e.Graphics.DrawRectangle(pen, 0, 0, this.Width - 1, this.Height - 1);
            pen.Dispose();

            int width = this.Width - Padding.Left - Padding.Right;
            int height = this.Height - Padding.Top - Padding.Bottom;
            int size = Math.Min(width, height);
            int rowSize = size / _row;
            int columnSize = size / _column;
            int panX = width - columnSize * _column;
            int panY = height - rowSize * _row;
            width -= panX;
            height -= panY;
            panX = Padding.Left + (panX >> 1);
            panY = Padding.Top + (panY >> 1);

            DrawBlock(e.Graphics, width, height, panX, panY, rowSize, columnSize);
            DrawMap(e.Graphics, width, height, panX, panY, rowSize, columnSize);
            DrawRobot(e.Graphics, width, height, panX, panY, rowSize, columnSize);

            e.Graphics.Smooth(false);
        }
        private void DrawBlock(Graphics g, int width, int height, int panX, int panY, int rowSize, int columnSize)
        {
            Pen pen = new Pen(Color.Red);
            Brush brush = new SolidBrush(Color.Black);
            //for (int i = 0; i <= _row; i++)
            //{
            //    int y = panY + rowSize * i;
            //    g.DrawLine(pen, panX, y, width + panX, y);

            //}
            //for (int i = 0; i <= _column; i++)
            //{
            //    int x = panX + columnSize * i;
            //    g.DrawLine(pen, x, panY, x, panY + height);
            //}

            for (int i = 0; i < _row; i++)
            {
                for (int j = 0; j < _column; j++)
                {
                    int x = panX + j * columnSize;
                    int y = panY + i * rowSize;
                    g.FillEllipse(brush, x + ((columnSize - _blackSize) >> 1), y + ((rowSize - _blackSize) >> 1), _blackSize, _blackSize);
                }
            }
            pen.Dispose();
            brush.Dispose();
        }
        private void DrawMap(Graphics g, int width, int height, int panX, int panY, int rowSize, int columnSize)
        {
            if (_cellInfo == null) return;
            fixed (sbyte* ptr = _cellInfo.Map)
            {
                Brush brush = new SolidBrush(Color.Black);
                for (int i = 0; i < _row; i++)
                {
                    for (int j = 0; j < _column; j++)
                    {
                        sbyte* cur = ptr + i * _column + j;
                        if (*cur == 1)
                        {
                            int x = panX + j * columnSize;
                            int y = panY + i * rowSize;

                            g.FillRectangle(brush, x, y, columnSize, rowSize);
                        }
                    }
                }
                Brush brush2 = new SolidBrush(Color.Red);
                int x1 = panX + _cellInfo.End.X * columnSize + 5;
                int y1 = panY + _cellInfo.End.Y * rowSize + 5;
                g.FillEllipse(brush2, x1, y1, columnSize - 10, rowSize - 10);
                brush2.Dispose();
                brush.Dispose();
            }
        }
        private void DrawRobot(Graphics g, int width, int height, int panX, int panY, int rowSize, int columnSize)
        {
            if (_robotImage == null) return;

            int x = panX + _robotPoint.X * columnSize;
            int y = panY + _robotPoint.Y * rowSize;
            const int p = 5;
            int robotSizeR = rowSize - p;
            int robotSizeC = columnSize - p;

            // 计算图像中心点
            int centerX = x + ((columnSize) >> 1);
            int centerY = y + ((rowSize) >> 1);

            // 保存当前的状态
            GraphicsState graphicsState = g.Save();
            // 将图像中心设置为旋转中心
            g.TranslateTransform(centerX, centerY);
            // 应用旋转
            g.RotateTransform(_angle);
            // 绘制图像
            g.DrawImage(_robotImage, -(robotSizeC >> 1), -(robotSizeR >> 1), robotSizeC, robotSizeR);
            // 恢复到之前的状态
            g.Restore(graphicsState);
        }
        protected override void OnSizeChanged(EventArgs e)
        {
            this.Invalidate();
        }
    }
}
